﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace ZeroBug.EasyFlow.Core
{
    public class VariableExpression
    {
        private VariableManager _variableManager;
        public string VarExpName { get; set; }
        public List<string> Expressions { get; set; }
        public VariableType ExpressionDealVarType { get; set; }
        public VariableExpression()
        {
            this.Expressions = new List<string>();
        }
        public VariableExpression(string varExpName, VariableType varType = VariableType.Text)
            : this()
        {
            this.VarExpName = varExpName;
            this.ExpressionDealVarType = varType;
        }
        public void SetVariableManager(VariableManager variableManager)
        {
            this._variableManager = variableManager;
        }
        public Variable GetEquivalent(string name = "")
        {
            List<string> vals = new List<string>();
            for (int i = 0; i < this.Expressions.Count; i++)
            {
                if (this.Expressions[i].StartsWith('@'))
                {
                    string exp = this.Expressions[i].Replace("@", "");
                    if (this.ExpressionDealVarType == VariableType.Numeric && !string.IsNullOrEmpty(exp))
                    {
                        Variable v = getExpressionValue(exp, VariableType.Numeric);
                        for (int j = 0; j < v.Count; j++)
                        {
                            vals.Add(v[j]);
                        }
                    }
                    else if (this.ExpressionDealVarType == VariableType.Text && !string.IsNullOrEmpty(exp))
                        vals.Add(getExpressionValueString(exp));
                    else if (this.ExpressionDealVarType == VariableType.Boolean && !string.IsNullOrEmpty(exp))
                    {
                        Variable v = getExpressionValue(exp, VariableType.Boolean);
                        for (int j = 0; j < v.Count; j++)
                        {
                            vals.Add(v[j]);
                        }
                    }
                }
                else
                    vals.Add(this.Expressions[i]);
            }
            return new Variable(name, vals.ToArray(), ExpressionDealVarType);
        }
        public void ResolveExpression(string expression)
        {
            //去掉括号
            string finalString = string.Empty;
            List<string> subStrings = new List<string>();
            getStringByInnerParentheses(expression, subStrings, ref finalString);
            if(subStrings.Count > 0)
            {

            }
            else
            {

            }
        }
        private Variable getExpressionValue(string expression, VariableType varType)
        {
            string pattern = @"(.*?)\.(Fetch|IndexOf|Count|Any)\((.*?)\)";
            Regex regex = new Regex(pattern);
            MatchCollection matches = regex.Matches(expression);
            if(matches.Count > 0)
            {
                string numericExp = matches[0].Groups[1].Value;

                MatchCollection numMatches = Regex.Matches(numericExp, @"\[([^\]]+)\]");
                List<string> finalExp = new List<string>();
                List<string> varNames = new List<string>();
                foreach (Match match in numMatches)
                {
                    varNames.Add(match.Value.Replace("[", "").Replace("]", ""));
                }
                for (int i = 0; i < _variableManager.GetVariable(varNames[0]).Count; i++)
                {
                    string result = numericExp;
                    for (int j = 0; j < varNames.Count; j++)
                    {
                        result = result.Replace($"[{varNames[j]}]", _variableManager.GetVariable(varNames[j])[i]);
                    }
                    finalExp.Add(result);
                }

                Variable var1 = new Variable("", finalExp.Select(s => Calculator.Evaluate(s).ToString()).ToArray(), varType);
                string paramName = matches[0].Groups[3].Value.Replace("[", "").Replace("]", "");
                string function = matches[0].Groups[2].Value;
                Variable param = _variableManager.GetVariable(paramName) ?? new Variable("fixed", paramName, varType);
                switch (function)
                {
                    case "Fetch":
                        return new Variable("", var1[Convert.ToInt32(param[0])], varType);
                    case "IndexOf":
                        return new Variable("", var1.IndexOf(param[0]).ToString(), varType);
                    case "Count":
                        return new Variable("", var1.Count.ToString(), varType);
                    case "Any":
                        return new Variable("", var1.Any(v => v.Equals(param[0])).ToString(), varType);
                }
            }
            //else if (matches.Count == 1)
            //{
            //    MatchCollection numMatches = Regex.Matches(expression, @"\[([^\]]+)\]");
            //    List<string> finalExp = new List<string>();
            //    List<string> varNames = new List<string>();
            //    foreach (Match match in numMatches)
            //    {
            //        varNames.Add(match.Value.Replace("[", "").Replace("]", ""));
            //    }
            //    for (int i = 0; i < _variableManager.GetVariable(varNames[0]).Count; i++)
            //    {
            //        string result = expression;
            //        for (int j = 0; j < varNames.Count; j++)
            //        {
            //            result = result.Replace($"[{varNames[j]}]", _variableManager.GetVariable(varNames[j])[i]);
            //        }
            //        finalExp.Add(result);
            //    }
            //    return new Variable("", finalExp.Select(s => Calculator.Evaluate(s).ToString()).ToArray(), varType);
            //}
            else
                return getVariableExpressionValue(expression, varType);
            return null;
        }
        private string getExpressionValueString(string expression)
        {
            string finalString = string.Empty;
            List<string> subStrings = new List<string>();
            getStringByInnerParentheses(expression, subStrings, ref finalString);
            if (subStrings.Count > 0)
            {
                for (int i = 0; i < subStrings.Count; i++)
                {
                    string value = getExpressionValueString(subStrings[i]);
                    if (value != null)
                    {
                        finalString = finalString.Replace($"[varTemp{i}]", value);
                    }
                }
                return getExpressionValueString(finalString);
            }
            else
            {
                // 定义正则表达式模式
                // 使用管道符 | 来表示“或”关系，匹配 Sin, Cos, 或 Tan
                string pattern = @"(.*?)\.(Split|Fetch|Combine|IndexOf|Subtract|Count|Any)\((.*?)\)";
                Regex regex = new Regex(pattern);
                MatchCollection matches = regex.Matches(expression);
                if (matches.Count > 1)
                {
                    Variable varBefore = null;
                    //如果匹配的个数大于 1个，从左往右，依次计算
                    //[var1].Split(,).Fetch(1).Combine(bbb)
                    // 遍历匹配结果
                    int index = 0;
                    foreach (Match match in matches)
                    {
                        string var1Name = match.Groups[1].Value.Replace("[", "").Replace("]", "");
                        string paramName = match.Groups[3].Value.Replace("[", "").Replace("]", "");
                        string function = match.Groups[2].Value;

                        Variable? var1 = index > 0 ? varBefore : _variableManager.GetVariable(var1Name);
                        Variable param = _variableManager.GetVariable(paramName) ?? new Variable("fixed", paramName, VariableType.Text);

                        switch (function)
                        {
                            case "Split":
                                varBefore = new Variable("varTemp", var1[0].Split(param[0]), VariableType.Text);
                                break;
                            case "Fetch":
                                varBefore = new Variable("varTemp", var1[Convert.ToInt32(param[0])], VariableType.Text);
                                break;
                            case "Combine":
                                varBefore = new Variable("varTemp", $"{varBefore[0]}{param[0]}", VariableType.Text);
                                break;
                            case "IndexOf":
                                varBefore = new Variable("varTemp", var1.IndexOf(param[0]).ToString(), VariableType.Text);
                                break;
                            case "Subtract":
                                string[] strs = param[0].Split(',');
                                if (strs.Length > 1)
                                    varBefore = new Variable("varTemp", var1[0].Substring(Convert.ToInt32(strs[0]), Convert.ToInt32(strs[1])), VariableType.Text);
                                else
                                    varBefore = new Variable("varTemp", var1[0].Substring(Convert.ToInt32(strs[0])), VariableType.Text);
                                break;
                            case "Count":
                                varBefore = new Variable("varTemp", var1.Count.ToString(), VariableType.Text);
                                break;
                            case "Any":
                                varBefore = new Variable("varTemp", var1.Any(v => v.Equals(param[0])).ToString(), VariableType.Text);
                                break;
                        }
                        index++;
                    }
                    return varBefore[0];
                }
                else if(matches.Count == 1)
                {
                    string var1Name = matches[0].Groups[1].Value.Replace("[", "").Replace("]", "");
                    string paramName = matches[0].Groups[3].Value.Replace("[", "").Replace("]", "");
                    string function = matches[0].Groups[2].Value;
                    Variable var1 = _variableManager.GetVariable(var1Name);
                    Variable param = _variableManager.GetVariable(paramName) ?? new Variable("fixed", paramName, VariableType.Text);
                    switch (function)
                    {
                        case "Split":
                            return var1[0];
                        case "Fetch":
                            return var1[Convert.ToInt32(param[0])];
                        case "Combine":
                            break;
                        case "IndexOf":
                            return var1.IndexOf(param[0]).ToString();
                        case "Subtract":
                            string[] strs = param[0].Split(',');
                            return strs.Length > 1 ? var1[0].Substring(Convert.ToInt32(strs[0]), Convert.ToInt32(strs[1])) : var1[0].Substring(Convert.ToInt32(strs[0]));
                        case "Count":
                            return var1.Count.ToString();
                        case "Any":
                            return var1.Any(v => v.Equals(param[0])).ToString();
                    }
                }
                else
                {
                    return getVariableExpressionValue(expression, VariableType.Text)[0];
                }
                return expression;
            }
        }
        private void getStringByInnerParentheses(string input, List<string> subStrings, ref string finalString)
        {
            int count = 0;
            int startIndex = -1;
            int endIndex = -1;
            string subString = string.Empty;
            int innerLevel = 0;

        start:
            count = 0;
            for (int i = 0; i < input.Length; i++)
            {
                char c = input[i];
                if (input[i].Equals('('))
                {
                    if (count == 0)
                        startIndex = i;
                    //左括号数量++
                    count++;
                }
                if (input[i].Equals(')'))
                {
                    count--;
                    if (count == 1)
                    {
                        endIndex = i;
                        subString = input.Substring(startIndex + 1, endIndex - startIndex);
                        subStrings.Add(subString);
                        finalString = input.Replace(subString, $"[varTemp{innerLevel}]");
                        innerLevel++;
                        input = finalString;
                        goto start;
                    }
                }
            }
        }
        private Variable getVariableExpressionValue(string expression, VariableType varType)
        {
            MatchCollection numMatches = Regex.Matches(expression, @"\[([^\]]+)\]");
            List<string> finalExp = new List<string>();
            List<string> varNames = new List<string>();
            foreach (Match match in numMatches)
            {
                varNames.Add(match.Value.Replace("[", "").Replace("]", ""));
            }
            for (int i = 0; i < _variableManager.GetVariable(varNames[0]).Count; i++)
            {
                string result = expression;
                for (int j = 0; j < varNames.Count; j++)
                {
                    result = result.Replace($"[{varNames[j]}]", _variableManager.GetVariable(varNames[j])[i]);
                }
                finalExp.Add(result);
            }
            if (varType == VariableType.Numeric)
                return new Variable("", finalExp.Select(s => Calculator.Evaluate(s).ToString()).ToArray(), VariableType.Numeric);
            else
                return new Variable("", finalExp.ToArray(), varType);
        }
        public override string ToString()
        {
            return string.Join(",", Expressions);
        }
        public bool IsEmpty()
        {
            return Expressions == null || Expressions.Count == 0;
        }
    }
}
